package com.lagou.edu.annotation.handler;

import com.google.common.collect.Sets;
import com.lagou.edu.annotation.Autowired;
import com.lagou.edu.annotation.Repository;
import com.lagou.edu.annotation.Service;
import com.lagou.edu.annotation.Transactional;
import com.lagou.edu.factory.ProxyFactory;

import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLDecoder;
import java.util.*;
import java.util.stream.Collectors;

public class AnnoHandler {

    //根据路径获取所有的类并筛选出添加了@Service以及@Repository的类，将其存储到map中
    public static void component(String path, Map<String, Object> map) throws Exception {
        Set<Class<?>> classes = null;
        try {
            classes = getClassByPath(path);
        } catch (IOException e) {
            System.err.println("捕获IoException");
        }
        Set<Class<?>> collect = classes.stream().filter(clazz -> null != clazz.getAnnotation(Service.class) || null != clazz.getAnnotation(Repository.class)).collect(Collectors.toSet());

        for (Class<?> clazz : collect) {
            if (null != clazz.getAnnotation(Service.class))
                map.put(clazz.getAnnotation(Service.class).value(), clazz.getConstructor().newInstance());
            else
                map.put(clazz.getAnnotation(Repository.class).value(), clazz.getConstructor().newInstance());
        }
    }

    public static void autowired(Object object, Map<String, Object> map) {
        Class<?> clazz = object.getClass();
        Field[] declaredFields = clazz.getDeclaredFields();
        Arrays.stream(declaredFields).filter(field -> null != field.getAnnotation(Autowired.class)).forEach(field -> {
            Autowired annotation = field.getAnnotation(Autowired.class);
            try {
                field.setAccessible(true);
                field.set(object, map.get(annotation.value()));
            } catch (IllegalAccessException e) {
                System.err.println("设置属性失败");
            }
        });
    }

    public static void transactional(Object object, Map<String, Object> map) {

        Class<?> clazz = object.getClass();
        Method[] methods = clazz.getDeclaredMethods();
        Arrays.stream(methods).filter(method -> 0 != method.getAnnotationsByType(Transactional.class).length).forEach(method -> {
            ProxyFactory factory = (ProxyFactory) map.get("proxyFactory");
            map.put(object.getClass().getAnnotation(Service.class).value(), factory.getJdkProxy(object));
        });
    }

    private static Set<Class<?>> getClassByPath(String path) throws IOException {
        Set<Class<?>> set = Sets.newHashSet();
        boolean recursive = true;
        // 包名对应的路径名称
        String packageDirName = path.replace('.', '/');
        Enumeration<URL> dirs;

        dirs = Thread.currentThread().getContextClassLoader().getResources(packageDirName);
        while (dirs.hasMoreElements()) {

            URL url = dirs.nextElement();
            String protocol = url.getProtocol();

            if ("file".equals(protocol)) {
                String filePath = URLDecoder.decode(url.getFile(), "UTF-8");
                findClassInPackageByFile(path, filePath, recursive, set);
            }
        }
        return set;
    }

    private static void findClassInPackageByFile(String packageName, String filePath, final boolean recursive,
                                                 Set<Class<?>> clazzs) {
        File dir = new File(filePath);
        if (!dir.exists() || !dir.isDirectory()) {
            return;
        }
        // 在给定的目录下找到所有的文件，并且进行条件过滤
        File[] dirFiles = dir.listFiles(new FileFilter() {

            public boolean accept(File file) {
                boolean acceptDir = recursive && file.isDirectory();// 接受dir目录
                boolean acceptClass = file.getName().endsWith("class");// 接受class文件
                return acceptDir || acceptClass;
            }
        });

        for (File file : dirFiles) {
            if (file.isDirectory()) {
                findClassInPackageByFile(packageName + "." + file.getName(), file.getAbsolutePath(), recursive, clazzs);
            } else {
                String className = file.getName().substring(0, file.getName().length() - 6);
                try {
                    clazzs.add(Thread.currentThread().getContextClassLoader().loadClass(packageName + "." + className));
                } catch (ClassNotFoundException e) {
                    System.err.println("找不到该类 ： " + className);
                } catch (NoClassDefFoundError e) {
                    System.err.println("找不到该类 ： " + className);
                }
            }
        }
    }
}
